package cn.iocoder.springboot.lab03.kafkademo.service;

import com.google.common.cache.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;

/**
 * @Author：YH
 * @Description：
 * @Date:Created in 2023/12/16 22:13
 */
@Service
@Slf4j
public class PositionServiceImpl {

    @Resource
    private RedisTemplate<String, String> redisTemplate;

    private static Cache<String, String> cache =
            CacheBuilder.newBuilder()
                    .expireAfterWrite(5, TimeUnit.SECONDS)
                    .build();

    private static LoadingCache<String, String> cacheLoadInit = CacheBuilder.newBuilder()
            .initialCapacity(5)
            .maximumSize(100)
            .expireAfterWrite(20000, TimeUnit.MILLISECONDS)
            .removalListener(new RemovalListener<String, String>() {
                @Override
                public void onRemoval(RemovalNotification<String, String> removalNotification) {
                    log.info(removalNotification.getKey() + ":remove==> :" + removalNotification.getValue());
                }
            })
            .build(new CacheLoader<String, String>() {
                @Override
                public String load(String key) throws Exception {
                    log.info("[method1]加载数据:{}", key);
                    return key + "业务数据生成Value";
                }
            });

    public void testMethode() throws ExecutionException, InterruptedException {
        //由于CacheLoader可能抛出异常,LoadingCache.get(K)也声明为抛出ExecutionException异常
        String key = cacheLoadInit.get("first-name");
        log.info("first:{}", key);
        String key2 = cacheLoadInit.get("first-name");
        log.info("second:{}", key2);
//        TimeUnit.MILLISECONDS.sleep(5000);
//        //设置了5s的过期时间,5s后会重新加载缓存
//        String keySecond = cacheLoadInit.get("first-name");
//        System.out.println("5s后重新加载缓存数据" + keySecond);
    }

    private static void method1() throws ExecutionException, InterruptedException {
        LoadingCache<String, String> build = CacheBuilder.newBuilder()
                .initialCapacity(5)
                .maximumSize(100)
                .expireAfterWrite(5000, TimeUnit.MILLISECONDS)
                .removalListener(new RemovalListener<String, String>() {
                    @Override
                    public void onRemoval(RemovalNotification<String, String> removalNotification) {
                        log.info(removalNotification.getKey() + ":remove==> :" + removalNotification.getValue());
                    }
                })
                .build(new CacheLoader<String, String>() {
                    @Override
                    public String load(String key) throws Exception {
                        log.info("[method1]加载数据:{}", key);
                        return key;
                    }
                });


        LoadingCache<String, String> cacheLoadInit = CacheBuilder
                .newBuilder()
                .initialCapacity(5)
                .maximumSize(100)
                .expireAfterWrite(5000, TimeUnit.MILLISECONDS) //
                .removalListener(new RemovalListener<String, String>() {
                    @Override
                    public void onRemoval(RemovalNotification<String, String> removalNotification) {
                        System.out.println(removalNotification.getKey() + ":remove==> :" + removalNotification.getValue());
                    }
                })
                .build(
                        new CacheLoader<String, String>() {
                            @Override
                            public String load(String key) throws Exception {
                                System.out.println("first init.....");
                                return key;
                            }
                        });
        //由于CacheLoader可能抛出异常,LoadingCache.get(K)也声明为抛出ExecutionException异常
        String key = cacheLoadInit.get("first-name");
        String key2 = cacheLoadInit.get("first-name");
        System.out.println(key);
        TimeUnit.MILLISECONDS.sleep(5000);
        System.out.println("==========");
        //设置了5s的过期时间,5s后会重新加载缓存
        String keySecond = cacheLoadInit.get("first-name");
        System.out.println("5s后重新加载缓存数据" + keySecond);
        /**
         * first init.....
         * first-name
         * ==========
         * first init.....
         * 5s后重新加载缓存数据first-name
         */
    }


    public String getHotPosition() throws ExecutionException {
        //从guava本地缓存中获取数据,如果没有则从redis中回源
        String value = cache.get("position", new Callable<String>() {
            @Override
            public String call() throws Exception {
                log.info("触发从本地缓存读取数据");
                return getHotPositionListFromRedis();
            }
        });
        if (value != null) {
            return value;
        }
        return null;
    }

    public String getHotPositionListFromRedis() {
        String position = redisTemplate.opsForValue().get("position");
        if (position == null) {
            //从mysql中获取数据
            String positionList = "数据库读到数据";
            log.info("从数据库读数据");
            //同步至redis
            redisTemplate.opsForValue().set("position", positionList, 15, TimeUnit.SECONDS);
            log.info("写入数据到二级缓存redis");
            //getHotPositionListFromRedis在guava不存在的时候调用,这里会将数据写入到guava本地缓存中
            return positionList;
        }
        return position;
    }
}
